; gdi+ ahk tutorial 7 written by tic (Tariq Porter)
; Requires Gdip.ahk either in your Lib folder as standard library or using #Include
;
; Tutorial to draw a rounded rectangle as a gui that you can drag

#SingleInstance, Force
#NoEnv
SetBatchLines, -1

; Uncomment if Gdip.ahk is not in your standard library
; #Include, Gdip.ahk

; Start gdi+
If !pToken := Gdip_Startup()
{
	MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system
	ExitApp
}
OnExit, Exit

; Set the width and height we want as our drawing area, to draw everything in. This will be the dimensions of our bitmap
Width := A_ScreenWidth, Height := A_ScreenHeight

; Create a layered window (+E0x80000 : must be used for UpdateLayeredWindow to work!) that is always on top (+AlwaysOnTop), has no taskbar entry or caption
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +OwnDialogs

; Show the window
Gui, 1: Show, NA

; Get a handle to this window we have created in order to update it later
hwnd1 := WinExist()

; Create a gdi bitmap with width and height of what we are going to draw into it. This is the entire drawing area for everything
hbm := CreateDIBSection(Width, Height)

; Get a device context compatible with the screen
hdc := CreateCompatibleDC()

; Select the bitmap into the device context
obm := SelectObject(hdc, hbm)

; Get a pointer to the graphics of the bitmap, for use with drawing functions
G := Gdip_GraphicsFromHDC(hdc)

; Set the smoothing mode to antialias = 4 to make shapes appear smother (only used for vector drawing and filling)
Gdip_SetSmoothingMode(G, 3)

; Create a partially transparent, black brush (ARGB = Transparency, red, green, blue) to draw a rounded rectangle with
pBrush := Gdip_BrushCreateSolid(0xFF000000)

; Fill the graphics of the bitmap with a rounded rectangle using the brush created
; Filling the entire graphics - from coordinates (0, 0) the entire width and height
; The last parameter (20) is the radius of the circles used for the rounded corners
Gdip_FillRectangle(G, pBrush, 0, 0, Width, Height)

; Delete the brush as it is no longer needed and wastes memory
Gdip_DeleteBrush(pBrush)


; Update the specified window we have created (hwnd1) with a handle to our bitmap (hdc), specifying the x,y,w,h we want it positioned on our screen
; With some simple maths we can place the gui in the centre of our primary monitor horizontally and vertically at the specified heigth and width
UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)

; By placing this OnMessage here. The function WM_LBUTTONDOWN will be called every time the user left clicks on the gui
OnMessage(0x201, "WM_LBUTTONDOWN")


; Select the object back into the hdc
; SelectObject(hdc, obm)

; Now the bitmap may be deleted
; DeleteObject(hbm)

; Also the device context related to the bitmap may be deleted
; DeleteDC(hdc)

; The graphics ma0 now be deleted
; Gdip_DeleteGraphics(G)

SQUARESIZE := 20
XPOS := 0
YPOS := 0
COLORBASE := 0xED1C24
RANGE := 1


Loop, {

DCOLOR := ColorVary(COLORBASE,RANGE)

BrushColor := 0xFF000000 + DCOLOR
pBrush := Gdip_BrushCreateSolid(BrushColor)
Gdip_FillRectangle(G, pBrush, XPOS, YPOS, SQUARESIZE, SQUARESIZE)

XPOS += SQUARESIZE
If (XPOS > A_ScreenWidth)
	{
	XPOS := 0
	YPOS += SQUARESIZE
	}
If (YPOS > A_ScreenHeight)
	{
	YPOS := 0
	XPOS := 0
	}


UpdateLayeredWindow(hwnd1, hdc, 0, 0, Width, Height)
Gdip_DeleteBrush(pBrush)

}

Return ; End of Auto-Execute

;#######################################################################

; This function is called every time the user clicks on the gui
; The PostMessage will act on the last found window (this being the gui that launched the subroutine, hence the last parameter not being needed)
WM_LBUTTONDOWN()
{
	PostMessage, 0xA1, 2
}

;#######################################################################


Esc::
Exit:
; gdi+ may now be shutdown on exiting the program
Gdip_Shutdown(pToken)
ExitApp
Return

ChannelVary(ByRef CBase, Range)
{
; CBase is already defined (single channel)
; Deviate Range is already defined (omnichannel)
Random, Deviate, 0, 255
Random, DeviateRandom, 0.0, 1.0

If (Range <= 1)
	DeviateUpperBound := Range
Else
	DeviateUpperBound := 1

If (Range <= 1)
	DeviateLowerBound := 0
Else
	DeviateLowerBound := Range-1

DeviateSubStrength := ((DeviateUpperBound-DeviateLowerBound)/(1-0))*(DeviateRandom-0)+DeviateLowerBound
StrengthExponent := 13.962*Range + 0.2377
DeviateStrength := DeviateSubStrength**StrengthExponent
CBase := Round(Deviate*DeviateStrength + CBase*(1-DeviateStrength))

}

ColorVary(Base, Range)
{
RBase := 0
GBase := 0
BBase := 0

ChannelSplit(RBase, GBase, BBase, Base)

ChannelVary(RBase, Range)
ChannelVary(GBase, Range)
ChannelVary(BBase, Range)

; Recombine channels
NewBase := (RBase<<16) + (GBase<<8) + BBase
Return, NewBase

}

ChannelSplit(ByRef Red, ByRef Green, ByRef Blue, RGBColor)
{
Red := (RGBColor>>16)&255
Green := (RGBColor>>8)&255
Blue := (RGBColor)&255
}
